﻿using System.Collections.Generic;
using System.Text.Json.Serialization;
using LightCAD.MathLib;
namespace LightCAD.Core.Elements
{
    /// <summary>
    /// 转角标注（线性）
    /// </summary>
    public class DimRotated : LcElement
    {
        //标注两边的线第一根线的起点
        [JsonInclude, JsonPropertyName("F")]
        [JsonConverter(typeof(Vector2dConverter))]
        public Vector2 First;
        //标注两边的线第二根线的起点
        [JsonInclude, JsonPropertyName("S")]
        [JsonConverter(typeof(Vector2dConverter))]
        public Vector2 Second;
        //标注两边的线的结束点
        [JsonInclude, JsonPropertyName("T")]
        [JsonConverter(typeof(Vector2dConverter))]
        public Vector2 Third;

        //标注底线的线的中心点
        [JsonInclude, JsonPropertyName("Fifth")]
        [JsonConverter(typeof(Vector2dConverter))]
        public Vector2 Fifth;
        //垂直
        public string Vertical;

        public DimRotated()
        {
            this.Type = BuiltinElementType.DimRotated;
        }
        public DimRotated(Vector2 first, Vector2 second, Vector2 third,bool vertical) : this()
        {
            this.First = first;
            this.Second = second;
            this.Third = third;
            if (vertical)
            {
                this.Vertical = "vertical";
                this.Fifth = new Vector2((this.First.X + this.Second.X) / 2, this.Third.Y);
            }
            else
            {
                this.Vertical = "horizontal";
                this.Fifth = new Vector2(this.Third.X, (this.First.Y + this.Second.Y) / 2);
            }
        }
        public DimRotated(double startX, double startY, double endX, double endY) : this()
        {
            this.First.X = startX;
            this.First.Y = startY;
            this.Second.X = endX;
            this.Second.Y = endY;
        }
        public LcText Text { get; set; }

        public double Length
        {
            get
            {
                if (this.Vertical == "vertical")
                    return (new Vector2(this.Second.X, this.Third.Y) - new Vector2(this.First.X, this.Third.Y)).Length();
                else
                    return (new Vector2(this.Third.X, this.Second.Y) - new Vector2(this.Third.X, this.First.Y)).Length();
            }
        }

        [JsonIgnore]
        public double Angle
        {
            get
            {
                return (this.Second - this.First).Angle();
            }
        }

        [JsonIgnore]
        public double DeltaX
        {
            get
            {
                return this.Second.X - this.First.X;
            }
        }

        [JsonIgnore]
        public double DeltaY
        {
            get
            {
                return this.Second.Y - this.First.Y;
            }
        }

        public override LcElement Clone()
        {
            var clone = new DimRotated();
            clone.Copy(this);
            return clone;
        }

        public override void Copy(LcElement src)
        {
            var dim = ((DimRotated)src);
        }
        public void Set(Vector2 first = null, Vector2 second = null, Vector2 third = null, bool fireChangedEvent = true)
        {
            //PropertySetter:Start,End
            if (!fireChangedEvent)
            {
                if (first != null) this.First = first;
                if (second != null) this.Second = second;
                if (third != null) this.Third = third;
            }
            else
            {
                bool chg_start = (first != null && first != this.First);
                if (chg_start)
                {
                    OnPropertyChangedBefore(nameof(First), this.First, first);
                    var oldValue = this.First;
                    this.First = first;
                    OnPropertyChangedAfter(nameof(First), oldValue, this.First);
                }
                bool chg_end = (second != null && second != this.Second);
                if (chg_end)
                {
                    OnPropertyChangedBefore(nameof(Second), this.Second, second);
                    var oldValue = this.Second;
                    this.Second = second;
                    OnPropertyChangedAfter(nameof(Second), oldValue, this.Second);
                }
                bool chg_third = (third != null && third != this.Third);
                if (chg_third)
                {
                    OnPropertyChangedBefore(nameof(Second), this.Second, second);
                    var oldValue = this.Second;
                    this.Third = third;
                    this.Fifth = third;
                    OnPropertyChangedAfter(nameof(Second), oldValue, this.Second);
                }
            }
        }
        public override Box2 GetBoundingBox()
        {
            if (this.Vertical == "vertical")
                return new Box2().SetFromPoints(new Vector2(this.First.X, this.Third.Y), this.Second);
            else
                return new Box2().SetFromPoints(new Vector2(this.Third.X, this.First.Y), this.Second);
        }
        public override Box2 GetBoundingBox(Matrix3 matrix)
        {
            if (this.Vertical == "vertical")
                return new Box2().SetFromPoints(matrix.MultiplyPoint(new Vector2(this.First.X, this.Third.Y)), matrix.MultiplyPoint(this.Second));
            else
                return new Box2().SetFromPoints(matrix.MultiplyPoint(new Vector2(this.Third.X, this.First.Y)), matrix.MultiplyPoint(this.Second));
        }
        public override bool IntersectWithBox(Polygon2d testPoly, List<RefChildElement> intersectChildren = null)
        {
            var thisBox = this.BoundingBox;
            //if (!thisBox.IntersectWith(testPoly.BoundingBox))
            //{
            //    //如果元素盒子，与多边形盒子不相交，那就可能不相交
            //    return false;
            //}
            Vector2 newThirdPointS = new Vector2();
            Vector2 newThirdPointE = new Vector2();
            if (this.Vertical == "vertical")
            {
                if (this.Fifth.X < this.First.X && this.Fifth.X < this.Second.X)
                    newThirdPointS = new Vector2(this.Fifth.X, this.Third.Y);
                else
                    newThirdPointS = new Vector2(this.First.X, this.Third.Y);

                if (this.Fifth.X > this.First.X && this.Fifth.X > this.Second.X)
                    newThirdPointE = new Vector2(this.Fifth.X, this.Third.Y);
                else
                    newThirdPointE = new Vector2(this.Second.X, this.Third.Y);

                return GeoUtils.IsPolygonIntersectLine(testPoly.Points, this.First, new Vector2(this.First.X, this.Third.Y))
                || GeoUtils.IsPolygonContainsLine(testPoly.Points, this.First, new Vector2(this.First.X, this.Third.Y))
                || GeoUtils.IsPolygonIntersectLine(testPoly.Points, this.Second, new Vector2(this.Second.X, this.Third.Y))
                || GeoUtils.IsPolygonContainsLine(testPoly.Points, this.Second, new Vector2(this.Second.X, this.Third.Y))
                || GeoUtils.IsPolygonIntersectLine(testPoly.Points, newThirdPointS, newThirdPointE)
                || GeoUtils.IsPolygonContainsLine(testPoly.Points, newThirdPointS, newThirdPointE);
            }
            else
            {
                if (this.Fifth.Y < this.First.Y && this.Fifth.Y < this.Second.Y)
                    newThirdPointS = new Vector2(this.Third.X, this.Fifth.Y);
                else
                    newThirdPointS = new Vector2(this.Third.X, this.First.Y);

                if (this.Fifth.Y > this.First.Y && this.Fifth.Y > this.Second.Y)
                    newThirdPointE = new Vector2(this.Third.X, this.Fifth.Y);
                else
                    newThirdPointE = new Vector2(this.Third.X, this.Second.Y);

                return GeoUtils.IsPolygonIntersectLine(testPoly.Points, this.First, new Vector2(this.Third.X, this.First.Y))
               || GeoUtils.IsPolygonContainsLine(testPoly.Points, this.First, new Vector2(this.Third.X, this.First.Y))
               || GeoUtils.IsPolygonIntersectLine(testPoly.Points, this.Second, new Vector2(this.Third.X, this.Second.Y))
               || GeoUtils.IsPolygonContainsLine(testPoly.Points, this.Second, new Vector2(this.Third.X, this.Second.Y))
               || GeoUtils.IsPolygonIntersectLine(testPoly.Points, newThirdPointS, newThirdPointE)
               || GeoUtils.IsPolygonContainsLine(testPoly.Points, newThirdPointS, newThirdPointE);
            }
        }

        public override bool IncludedByBox(Polygon2d testPoly, List<RefChildElement> includedChildren = null)
        {
            var thisBox = this.BoundingBox;
            if (!thisBox.IntersectsBox(testPoly.BoundingBox))
            {
                return false;
            }
            return GeoUtils.IsPolygonContainsLine(testPoly.Points, this.First, this.Second);
        }
        public override void Move(Vector2 startPoint, Vector2 endPoint)
        {
            Matrix3 matrix3 = Matrix3.GetMove(startPoint, endPoint);
            this.Set(matrix3.MultiplyPoint(this.First), matrix3.MultiplyPoint(this.Second));
            ResetBoundingBox();
        }
        //public override void Scale(Vector2d basePoint, double scaleFactor)
        //{
        //    Matrix3d matrix3 = Matrix3d.Scale(scaleFactor, basePoint);
        //    this.Set(matrix3.MultiplyPoint(this.Start), matrix3.MultiplyPoint(this.End));
        //    ResetBoundingBox();
        //}
        //public override void Scale(Vector2d basePoint, Vector2d scaleVector)
        //{

        //    Matrix3d matrix3 = Matrix3d.Scale(scaleVector, basePoint);
        //    this.Set(matrix3.MultiplyPoint(this.Start), matrix3.MultiplyPoint(this.End));
        //    ResetBoundingBox();
        //}
    }
}
